package com.xrui.myexprparser;

import java.util.List;

public class ASTEvaluator extends ExprSyntaxBaseVisitor<Object> {
    @Override public Object visitFieldName(ExprSyntaxParser.FieldNameContext ctx) {
        System.out.println(ctx.getText());
        return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitLiteral(ExprSyntaxParser.LiteralContext ctx) {
        return ctx.getText();
       // return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitIntegerLiteral(ExprSyntaxParser.IntegerLiteralContext ctx) {
        return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitFloatLiteral(ExprSyntaxParser.FloatLiteralContext ctx) { return visitChildren(ctx); }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitExpressions(ExprSyntaxParser.ExpressionsContext ctx) {
        StringBuilder sql = new StringBuilder();

        List<ExprSyntaxParser.ExpressionContext> exprList =ctx.expression() ;

        boolean bFirst = true;
        for(ExprSyntaxParser.ExpressionContext expr:exprList){
            sql.append(" ");
            sql.append(visit(expr));
            if(bFirst){
                bFirst = false;
            }else{
                sql.append(ctx.COMMA(0).getText());
            }
        }
        return sql.toString();
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitQueryexpression(ExprSyntaxParser.QueryexpressionContext ctx) {
//        ExprSyntaxParser.ExpressionContext expression = ctx.expression();
//        Object result = null;
//        if(expression instanceof ExprSyntaxParser.IsExpressionContext){
//            result =  visitIsExpression((ExprSyntaxParser.IsExpressionContext) expression);
//        }else if( expression instanceof ExprSyntaxParser.NotExpressionContext){
//            result =  visitNotExpression((ExprSyntaxParser.NotExpressionContext) expression);
//        }
//        else if( expression instanceof ExprSyntaxParser.){
//            result =  visitNotExpression((ExprSyntaxParser.NotExpressionContext) expression);
//        }
        return visit(ctx.expression());

        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitIsExpression(ExprSyntaxParser.IsExpressionContext ctx) {
        StringBuilder isSql = new StringBuilder();
        Object predicateStr = visit( ctx.predicate());
        isSql.append(predicateStr);
        String isStr =   ctx.IS().getText();
        isSql.append(" ");
        isSql.append(isStr);
        if (ctx.NOT() != null){
            isSql.append(" ");
            isSql.append(ctx.NOT().getText());
        }
        isSql.append(" ");
        isSql.append(ctx.testValue.getText());
        return isSql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitNotExpression(ExprSyntaxParser.NotExpressionContext ctx) {
        StringBuilder notSql = new StringBuilder();

        notSql.append("NOT");

        notSql.append(" ");

        Object result = visit(ctx.expression());

        notSql.append(" ");
        notSql.append(result);

        return notSql.toString();

    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitLogicalExpression(ExprSyntaxParser.LogicalExpressionContext ctx) {

        StringBuilder logicalExprSql = new StringBuilder();
        Object leftExpr = visit(ctx.expression(0));
        Object rightExpr = visit(ctx.expression(1));

        logicalExprSql.append(leftExpr);
        logicalExprSql.append(" ");
        logicalExprSql.append(ctx.logicalOperator());
        logicalExprSql.append(" ");
        logicalExprSql.append(rightExpr);

        return logicalExprSql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitPredicateExpression(ExprSyntaxParser.PredicateExpressionContext ctx) {
        return visit(ctx.predicate());
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitExpressionAtomPredicate(ExprSyntaxParser.ExpressionAtomPredicateContext ctx) {
        return visit(ctx.expressionAtom());
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitBinaryComparisonPredicate(ExprSyntaxParser.BinaryComparisonPredicateContext ctx) {
        StringBuilder comparsionSql = new StringBuilder();
        Object leftResult  = visit(ctx.left);
        comparsionSql.append(" ");
        comparsionSql.append(leftResult);
        Object compareOper = ctx.comparisonOperator().getText();
        comparsionSql.append(" ");
        comparsionSql.append(compareOper);
        Object rightResult = visit(ctx.right);
        comparsionSql.append(" ");
        comparsionSql.append(rightResult);

        return comparsionSql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitInPredicate(ExprSyntaxParser.InPredicateContext ctx) {
        StringBuilder inPredicateSql = new StringBuilder();
        Object predicateResult = visit(ctx.predicate());
        inPredicateSql.append(" ");
        inPredicateSql.append(predicateResult);

        if (ctx.NOT() != null){
            inPredicateSql.append(" ");
            inPredicateSql.append(ctx.NOT().getText());
        }

        inPredicateSql.append(" ");
        inPredicateSql.append(ctx.IN().getText());

        inPredicateSql.append(" ");
        inPredicateSql.append(ctx.LPAREN());
        Object expressions = visit(ctx.expressions());
        inPredicateSql.append(expressions);

        return inPredicateSql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitBetweenPredicate(ExprSyntaxParser.BetweenPredicateContext ctx) {
        StringBuilder betweenPredicateSql = new StringBuilder();

        Object zeroPredicate = visit(ctx.predicate(0));
        Object firstPredicate = visit(ctx.predicate(1));
        Object secondPredicate = visit(ctx.predicate(2));

        betweenPredicateSql.append(" ");
        betweenPredicateSql.append(zeroPredicate);

        if(ctx.NOT() != null){
            betweenPredicateSql.append(" ");
            betweenPredicateSql.append(ctx.NOT().getText());
        }
        betweenPredicateSql.append(" ");
        betweenPredicateSql.append(ctx.BETWEEN().getText());

        betweenPredicateSql.append(" ");
        betweenPredicateSql.append(firstPredicate);

        betweenPredicateSql.append(" ");
        betweenPredicateSql.append(ctx.AND().getText());

        betweenPredicateSql.append(" ");
        betweenPredicateSql.append(secondPredicate);

        return betweenPredicateSql.toString();

        //return visitChildren(ctx);

    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitIsNullPredicate(ExprSyntaxParser.IsNullPredicateContext ctx) {
        StringBuilder isNullPredicateSql = new StringBuilder();

        Object predicateResult = visit(ctx.predicate());

        isNullPredicateSql.append(" ");
        isNullPredicateSql.append(predicateResult);

        isNullPredicateSql.append(" ");
        isNullPredicateSql.append(ctx.IS());


        isNullPredicateSql.append(" ");
        isNullPredicateSql.append(visit(ctx.nullNotnull()));

        return isNullPredicateSql.toString();
        //return visitChildren(ctx);

    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitLikePredicate(ExprSyntaxParser.LikePredicateContext ctx) {
        StringBuilder likeSql = new StringBuilder();
        likeSql.append(" ");
        likeSql.append(visit(ctx.predicate(0)));


        if(ctx.NOT() != null) {
            likeSql.append(" ");
            likeSql.append( ctx.NOT().getText());
        }

        likeSql.append(" ");
        likeSql.append(ctx.LIKE().getText());

        likeSql.append(" ");
        likeSql.append(visit(ctx.predicate(1)));

        if(ctx.STRING_LITERAL() != null) {
            likeSql.append(" ");
            likeSql.append(ctx.STRING_LITERAL());
        }

        return likeSql.toString();

        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitRegexpPredicate(ExprSyntaxParser.RegexpPredicateContext ctx) {
        StringBuilder sql = new StringBuilder();
        sql.append(" ");
        sql.append(visit(ctx.predicate(0)));


        if(ctx.NOT() != null) {
            sql.append(" ");
            sql.append( ctx.NOT().getText());
        }

        sql.append(" ");
        if(ctx.REGEXP() != null)
            sql.append(ctx.REGEXP().getText());

        if(ctx.RLIKE() != null)
            sql.append(ctx.RLIKE().getText());

        sql.append(" ");
        sql.append(visit(ctx.predicate(1)));



        return sql.toString();


        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitUnaryExpressionAtom(ExprSyntaxParser.UnaryExpressionAtomContext ctx) {
        StringBuilder sql = new StringBuilder();

        sql.append(" ");
        sql.append(visit( ctx.unaryOperator()));

        sql.append(" ");
        sql.append(visit(ctx.expressionAtom()));

        return sql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitConstantExpressionAtom(ExprSyntaxParser.ConstantExpressionAtomContext ctx) {
        System.out.println(ctx.getText());
        return visitConstant(ctx.constant());
        //return ctx.getText();
        //return visitChildren(ctx);

    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitFullColumnNameExpressionAtom(ExprSyntaxParser.FullColumnNameExpressionAtomContext ctx) {
        System.out.println(ctx.getText());
        return visitFieldName(ctx.fieldName());
        //return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitBitExpressionAtom(ExprSyntaxParser.BitExpressionAtomContext ctx) {
        StringBuilder sql = new StringBuilder();

        sql.append(" ");
        sql.append(visit(ctx.left));

        sql.append(" ");
        sql.append(visitBitOperator(ctx.bitOperator()));

        sql.append(" ");
        sql.append(visit(ctx.right));

        return sql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitNestedExpressionAtom(ExprSyntaxParser.NestedExpressionAtomContext ctx) {
        StringBuilder sql = new StringBuilder();

        sql.append(" ");
        sql.append(ctx.LPAREN());

        List<ExprSyntaxParser.ExpressionContext> exprList =ctx.expression() ;

        boolean bFirst = true;
        for(ExprSyntaxParser.ExpressionContext expr:exprList){
            sql.append(" ");
            sql.append(visit(expr));
            if(bFirst){
                bFirst = false;
            }else{
                sql.append(ctx.COMMA(0).getText());
            }
        }

        sql.append(" ");
        sql.append(ctx.RPAREN());

        return sql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitMathExpressionAtom(ExprSyntaxParser.MathExpressionAtomContext ctx) {
        StringBuilder sql = new StringBuilder();

        sql.append(" ");
        sql.append(visit(ctx.left));
        sql.append(visitMathOperator(ctx.mathOperator()));
        sql.append(visit(ctx.right));

        return sql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitExistsExpressionAtom(ExprSyntaxParser.ExistsExpressionAtomContext ctx) {
        StringBuilder sql = new StringBuilder();

        sql.append(" ");
        sql.append(ctx.EXISTS().getText());
        sql.append(ctx.LPAREN().getText());
        sql.append(visit(ctx.expression()));
        sql.append(ctx.RPAREN().getText());

        return sql.toString();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitConstant(ExprSyntaxParser.ConstantContext ctx) {
        if(ctx.literal() != null)
            return visitLiteral(ctx.literal());
        return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitUnaryOperator(ExprSyntaxParser.UnaryOperatorContext ctx) {

        return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitBitOperator(ExprSyntaxParser.BitOperatorContext ctx) {
        return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitMathOperator(ExprSyntaxParser.MathOperatorContext ctx) {
        return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitLogicalOperator(ExprSyntaxParser.LogicalOperatorContext ctx) {
        return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitComparisonOperator(ExprSyntaxParser.ComparisonOperatorContext ctx) {
        return ctx.getText();
        //return visitChildren(ctx);
    }
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation returns the result of calling
     * {@link #visitChildren} on {@code ctx}.</p>
     */
    @Override public Object visitNullNotnull(ExprSyntaxParser.NullNotnullContext ctx) {
        StringBuilder nullNotNullSql = new StringBuilder();
        nullNotNullSql.append(" ");

        if (ctx.NOT() != null)
             nullNotNullSql.append(ctx.NOT().getText());

        nullNotNullSql.append(" ");
        nullNotNullSql.append(ctx.NULL_LITERAL().getText());

        return nullNotNullSql.toString();
        //return visitChildren(ctx);
    }
}
